package com.polaris.live.utils.zego.beauty

import android.hardware.Camera
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.faceunity.wrapper.faceunity
import com.polaris.live.common.constant.AppConst
import com.polaris.live.common.util.associateNotNullStrict
import com.polaris.live.resp.back_resp.BeautyBean
import com.polaris.live.resp.back_resp.BeautyDataItem
import com.polaris.live.resp.back_resp.BeautyItem

/**
 * faceUnity，应用中同时只有一个线程可以使用
 *
 * @author Created by lucas on 2018/3/27 17:42
 */
class FaceUnity(
    private var mBeautyBytes: ByteArray?
) {

    /* 输入图像的纹理类型，默认 2D */
    private val mInputTextureType: Int = 0

    private var mBeautyArrays: IntArray? = null

    private var mIsPause = false
    private var mBeautyId = -1
    private var mFrame = 0

    private var mOnHandlerListener: OnHandlerListener? = null

    /**
     * 将其绑定到activity的生命周期上
     */
    fun observe(owner: LifecycleOwner) {
        owner.lifecycle.addObserver(object : LifecycleEventObserver {
            override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
                when (event) {
                    Lifecycle.Event.ON_RESUME -> {
                        post { onCreateUnity() }
                    }
                    Lifecycle.Event.ON_DESTROY -> {
                        post { onReleaseUnity() }

                        FaceManager.unbindFaceUnity(this@FaceUnity)

                        mBeautyBytes = null
                    }
                    else -> {}
                }
            }
        })
    }

    /**
     * 初始化美颜
     */
    private fun initUnity() {
        if (mBeautyBytes == null) {
            return
        }
        if (mIsPause) {
            return
        }
        if (mBeautyId != -1) {
            return
        }

        mBeautyId = faceunity.fuCreateItemFromPackage(mBeautyBytes)

        resetBeautyParams(FaceManager.getBeauty(), FaceManager.getBeautyFilter())

        val beautyArrays = mBeautyArrays
        if (beautyArrays == null || beautyArrays[0] != mBeautyId) {
            mBeautyArrays = intArrayOf(mBeautyId)
        }

        faceunity.fuSetUseTexAsync(1) //不开启的话部分手机会黑屏闪烁
    }

    private var mTrackingStatus = 0
    private var mDefaultOrientation = 0

    /**
     * 重置方向
     */
    fun resetTrackingStatus() {
        mTrackingStatus = 0
    }

    /**
     * 设置方向
     */
    fun setTrackOrientationFua(imageRotation: Int) {
        if (mTrackingStatus == 1) {
            return
        }
        mInputImageOrientation = imageRotation
        val rotation = createRotationMode()
        if (mDefaultOrientation == rotation) {
            return
        }
        post {
            mDefaultOrientation = rotation
            faceunity.fuSetDefaultRotationMode(rotation) //设置识别人脸默认方向，能够提高首次识别的速度
        }
        mTrackingStatus = 1
    }

    /**
     * 设置方向
     */
    fun setTrackOrientationX(rotation: Int) {
        if (mTrackingStatus == 1) {
            return
        }
        if (mDefaultOrientation == rotation) {
            return
        }
        post {
            mDefaultOrientation = rotation
            faceunity.fuSetDefaultRotationMode(rotation / 90) //设置识别人脸默认方向，能够提高首次识别的速度
        }
        mTrackingStatus = 1
    }

    /* 根据不同的 texture 类型和输入方向，修改 rotationMode */
    private fun createRotationMode(): Int {
        if (mInputTextureType == 0) {
            return faceunity.FU_ROTATION_MODE_0
        }

        var rotMode: Int = faceunity.FU_ROTATION_MODE_0
        val deviceOrientation = mDeviceOrientation
        val cameraType = mCurrentCameraType
        val inputImageOrientation = mInputImageOrientation
        if (inputImageOrientation == 270) {
            rotMode = if (cameraType == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                deviceOrientation / 90
            } else {
                if (deviceOrientation == 90) {
                    faceunity.FU_ROTATION_MODE_270
                } else if (deviceOrientation == 270) {
                    faceunity.FU_ROTATION_MODE_90
                } else {
                    deviceOrientation / 90
                }
            }
        } else if (inputImageOrientation == 90) {
            if (cameraType == Camera.CameraInfo.CAMERA_FACING_BACK) {
                rotMode = if (deviceOrientation == 90) {
                    faceunity.FU_ROTATION_MODE_270
                } else if (deviceOrientation == 270) {
                    faceunity.FU_ROTATION_MODE_90
                } else {
                    deviceOrientation / 90
                }
            } else {
                if (deviceOrientation == 0) {
                    rotMode = faceunity.FU_ROTATION_MODE_180
                } else if (deviceOrientation == 90) {
                    rotMode = faceunity.FU_ROTATION_MODE_270
                } else if (deviceOrientation == 270) {
                    rotMode = faceunity.FU_ROTATION_MODE_90
                }
            }
        }
        return rotMode
    }

    private var mCurrentCameraType: Int = Camera.CameraInfo.CAMERA_FACING_FRONT

    /* 输入图像的方向，默认前置相机 270 */
    private var mInputImageOrientation = 270

    /* 设备方向，默认竖屏 */
    private val mDeviceOrientation = 90

    /**
     * camera切换时需要调用
     *
     * @param currentCameraType     前后置摄像头ID
     * @param inputImageOrientation 方向
     */
    fun onCameraChange(currentCameraType: Int, inputImageOrientation: Int) {
        if (mCurrentCameraType == currentCameraType
            && mInputImageOrientation == inputImageOrientation
        ) {
            return
        }

        post {
            mCurrentCameraType = currentCameraType
            mInputImageOrientation = inputImageOrientation
            faceunity.fuOnCameraChange()
        }
    }

    /**
     * 渲染到纹理
     */
    fun renderToTexture(textureId: Int, width: Int, height: Int): Int {
        initUnity()
        if (mBeautyId == -1) {
            return textureId
        }
        var flags = mInputTextureType
        if (mCurrentCameraType != Camera.CameraInfo.CAMERA_FACING_FRONT) {
            flags = flags or faceunity.FU_ADM_FLAG_FLIP_X
        }

        val texId = faceunity.fuRenderToTexture(textureId, width, height, mFrame++, mBeautyArrays, flags)
        return if (texId > 0) {
            texId
        } else {
            textureId
        }
    }

    /**
     * 创建美颜
     */
    fun onCreateUnity() {
        mIsPause = false
    }

    /**
     * 释放美颜
     */
    fun onReleaseUnity() {
        mIsPause = true

        if (mBeautyId == -1) {
            return
        }

        faceunity.fuDestroyAllItems()
        faceunity.fuDone()
        faceunity.fuOnDeviceLost()

        mFrame = 0
        mBeautyId = -1
        mBeautyArrays = null
    }

    /**
     * 执行在gl线程
     */
    fun post(runnable: Runnable) {
        mOnHandlerListener?.onHandler(runnable)
    }

    /**
     * 设置handler调度
     *
     * @param l 回调
     */
    fun setOnHandlerListener(l: OnHandlerListener) {
        this.mOnHandlerListener = l
    }

    private fun applyBlur(data: BeautyDataItem?) {
        val map = data?.beautyItem?.associateNotNullStrict {
            it.type to it
        } ?: emptyMap()

        listOf(
            AppConst.Beautify.MEIBAI,
            AppConst.Beautify.MOPI,
            AppConst.Beautify.QINGXI,
            AppConst.Beautify.BAIYA,
            AppConst.Beautify.LIANGYAN
        ).forEach {
            applyBlur(it, map[it])
        }
    }

    fun applyBlur(type: Int, item: BeautyItem?) {
        val value = item?.intensity
        when (type) {
            AppConst.Beautify.MEIBAI -> {
                setBeautyParamWhitening(computeValue(value, 2f, AppConst.Beautify.DEFAULT_MEIBAI))
            }
            AppConst.Beautify.MOPI -> {
                setBeautyParamBlur(computeValue(value, 6f, AppConst.Beautify.DEFAULT_MOPI))
            }
            AppConst.Beautify.QINGXI -> {
                setBeautyParamRosy(computeValue(value, 2f, AppConst.Beautify.DEFAULT_QINGXI))
            }
            AppConst.Beautify.BAIYA -> {
                setBeautyParamTooth(computeValue(value, 1f, AppConst.Beautify.DEFAULT_BAIYA))
            }
            AppConst.Beautify.LIANGYAN -> {
                setBeautyParamEyesBright(computeValue(value, 1f, AppConst.Beautify.DEFAULT_LIANGYAN))
            }
        }
    }

    private fun applyDeform(data: BeautyDataItem?) {
        val map = data?.beautyItem?.associateNotNullStrict {
            it.type to it
        } ?: emptyMap()

        listOf(
            AppConst.DeformType.SHOULIAN,
            AppConst.DeformType.DAYAN,
            AppConst.DeformType.YANJINGWEIZHI,
            AppConst.DeformType.FAJIXIAN,
            AppConst.DeformType.XIABA,
            AppConst.DeformType.SHOUBI,
            AppConst.DeformType.BICHANG,
            AppConst.DeformType.ZUIXING
        ).forEach {
            applyDeform(it, map[it])
        }
    }

    fun applyDeform(type: Int, item: BeautyItem?) {
        val value = item?.intensity

        when (type) {
            AppConst.DeformType.SHOULIAN -> {
                setBeautyParamThinning(computeValue(value, 1f, AppConst.DeformType.DEFAULT_SHOULIAN))
            }
            AppConst.DeformType.DAYAN -> {
                setBeautyParamEnlarging(computeValue(value, 1f, AppConst.DeformType.DEFAULT_DAYAN))
            }
            AppConst.DeformType.YANJINGWEIZHI -> {
                setBeautyParamEyeRotate(computeValue(value, 1f, AppConst.DeformType.DEFAULT_YANJINGWEIZHI))
            }
            AppConst.DeformType.FAJIXIAN -> {
                setBeautyParamForehead(computeValue(value, 1f, AppConst.DeformType.DEFAULT_FAJIXIAN))
            }
            AppConst.DeformType.XIABA -> {
                setBeautyParamChin(computeValue(value, 1f, AppConst.DeformType.DEFAULT_XIABA))
            }
            AppConst.DeformType.SHOUBI -> {
                setBeautyParamNose(computeValue(value, 1f, AppConst.DeformType.DEFAULT_SHOUBI))
            }
            AppConst.DeformType.BICHANG -> {
                setBeautyParamNoseLong(computeValue(value, 1f, AppConst.DeformType.DEFAULT_BICHANG))
            }
            AppConst.DeformType.ZUIXING -> {
                setBeautyParamMouth(computeValue(value, 1f, AppConst.DeformType.DEFAULT_ZUIXING))
            }
        }
    }

    private fun applyFilter(data: BeautyDataItem?, beautyFilter: Int) {
        val item = data?.beautyItem?.findLast { it.type == beautyFilter }
        if (item != null) {
            applyFilter(item)
        }
    }

    fun applyFilter(item: BeautyItem?) {
        val value = computeValue(item?.intensity, 1f, 50)

        when (val filterEnum = BeautyFilterEnum.getFilterByType(item?.type)) {
            BeautyFilterEnum.ORIGIN -> {
                setBeautyParamFilter(BeautyFilterEnum.ORIGIN.fName)
            }
            else -> {
                setBeautyParamFilter(filterEnum.fName)
                setBeautyParamFilterLevel(value)
            }
        }
    }

    private fun computeValue(value: Int?, max: Float, defVal: Int): Float {
        val v = value ?: defVal

        return v * max * 100 / 10000f
    }

    fun resetBeautyParams(beautyBean: BeautyBean, beautyFilter: Int) {
        if (mBeautyId == -1) {
            return
        }

        //face_shape 为4时，为用户自定义的精细变形，开放了脸型相关参数，添加了窄脸小脸参数
        setBeautyParamFaceShape(4.0f)
        setBeautyParamBlurHeavy()
        setBeautyParamBlurType()

        val map = beautyBean.item.associateNotNullStrict {
            it.type to it
        }

        //美肤
        applyBlur(map[AppConst.Beautify.BEAUTIFY])

        //美型
        applyDeform(map[AppConst.DeformType.DEFORM])

        //滤镜
        applyFilter(map[AppConst.BeautifyFilter.FILTER], beautyFilter)
    }

    //滤镜
    fun setBeautyParamFilter(name: String?) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "filter_name", name)
    }

    //滤镜等级
    fun setBeautyParamFilterLevel(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "filter_level", level.toDouble())
    }

    //美型的种类
    fun setBeautyParamFaceShape(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "face_shape", level.toDouble())
    }

    //磨皮
    fun setBeautyParamBlur(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "blur_level", level.toDouble())
    }

    //清晰磨皮
    fun setBeautyParamBlurHeavy() {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "heavy_blur", 0.0)
    }

    //精细磨皮
    fun setBeautyParamBlurType() {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "blur_type", 2.0)
    }

    //美白
    fun setBeautyParamWhitening(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "color_level", level.toDouble())
    }

    //红润
    fun setBeautyParamRosy(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "red_level", level.toDouble())
    }

    //锐化
    fun setBeautyParamSharpen(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "sharpen", level.toDouble())
    }

    //亮眼
    fun setBeautyParamEyesBright(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "eye_bright", level.toDouble())
    }

    //美牙
    fun setBeautyParamTooth(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "tooth_whiten", level.toDouble())
    }

    //黑眼圈
    fun setBeautyParamBlackEyes(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "remove_pouch_strength", level.toDouble())
    }

    //去法令纹
    fun setBeautyParamNasolabial(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "remove_nasolabial_folds_strength", level.toDouble())
    }

    //瘦脸
    fun setBeautyParamThinning(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "cheek_thinning", level.toDouble())
    }

    //v脸
    fun setBeautyParamFaceV(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "cheek_v", level.toDouble())
    }

    //窄脸
    fun setBeautyParamFaceNarrow(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "cheek_narrow", level.toDouble())
    }

    //小脸
    fun setBeautyParamFaceSmall(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "cheek_small", level.toDouble())
    }

    //大眼
    fun setBeautyParamEnlarging(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "eye_enlarging", level.toDouble())
    }

    //圆眼
    fun setBeautyParamEyeCircle(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "intensity_eye_circle", level.toDouble())
    }

    //下巴
    fun setBeautyParamChin(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "intensity_chin", level.toDouble())
    }

    //额头
    fun setBeautyParamForehead(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "intensity_forehead", level.toDouble())
    }

    //瘦鼻
    fun setBeautyParamNose(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "intensity_nose", level.toDouble())
    }

    //嘴型
    fun setBeautyParamMouth(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "intensity_mouth", level.toDouble())
    }

    //开眼角
    fun setBeautyParamCanthus(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "intensity_canthus", level.toDouble())
    }

    //眼距
    fun setBeautyParamEyeSpace(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "intensity_eye_space", level.toDouble())
    }

    //眼睛角度
    fun setBeautyParamEyeRotate(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "intensity_eye_rotate", level.toDouble())
    }

    //长鼻
    fun setBeautyParamNoseLong(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "intensity_long_nose", level.toDouble())
    }

    //人中
    fun setBeautyParamPhiltrum(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "intensity_philtrum", level.toDouble())
    }

    //微笑嘴角
    fun setBeautyParamSmile(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "intensity_smile", level.toDouble())
    }

    //瘦颧骨
    fun setBeautyParamCheekbones(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "intensity_cheekbones", level.toDouble())
    }

    //瘦下颌骨
    fun setBeautyParamJawLower(level: Float) {
        if (mBeautyId == -1) {
            return
        }
        faceunity.fuItemSetParam(mBeautyId, "intensity_lower_jaw", level.toDouble())
    }
}

fun interface OnHandlerListener {

    fun onHandler(runnable: Runnable?)
}
